<template>
	<view class="page">
		<scroll-view :style="{height:(systemInfo.windowHeight-imPlaceholderheight)+'px'}" scroll-y :scroll-into-view="scrollIntoView" class="msg-list">
				<!-- 聊天item -->
				<chat-item v-for="(item,index) in messages" :key='index' :item="item"></chat-item>
				<view class="list-last-item" id="list-last-item" key="list-last-item">
					<!-- 高度为0的 最后一个元素用于方便滚动到最后一个元素 -->
				</view>
		</scroll-view>
		<!-- 底部聊天输入框 -->
		<!-- #ifdef APP-PLUS -->
		<view class="bottom">
			<chat-input-bar @focus="showLast()" @send="sendToSpark" :style="{paddingBottom:(keyboardHeight>0?systemInfo.safeAreaInsets.bottom/2:systemInfo.safeAreaInsets.bottom)+'px'}"/>
		</view>
		<!-- #endif -->
		<!-- #ifdef MP -->
		<view class="bottom" :style="{bottom:(keyboardHeight>0?keyboardHeight-systemInfo.safeAreaInsets.bottom:0)+'px',paddingBottom:systemInfo.safeAreaInsets.bottom+'px'}">
			<chat-input-bar @focus="showLast()"  @send="sendToSpark" />
		</view>
		<!-- #endif -->
		
		<!-- #ifdef H5 -->
		<view class="bottom">
			<chat-input-bar @focus="showLast()"  @send="sendToSpark" />
		</view>
		<!-- #endif -->
	</view>
</template>

<script>
	import * as base64 from "base-64"
	import CryptoJS from '../../static/crypto-js/crypto-js.js'
	import parser from '../../static/fast-xml-parser/src/parser'
	import * as utf8 from "utf8"
	import URL from 'url'
	// const cAi = uniCloud.importObject('c-ai',{customUI:true})
	export default {
		data() {
			return {
				TEXT: '你好，我的名字叫大王',
				// 地址必须填写，代表着大模型的版本号！！！！！！！！！！！！！！！！wss://spark-api.xf-yun.com/v3.1/chat
				httpUrl: "https://spark-api.xf-yun.com/v3.1/chat",
				modelDomain: '', // V1.1-V3.5动态获取，高于以上版本手动指定
				APPID: '9125e4b0', // 控制台获取填写
				APISecret: 'M2YzNTIxNzk2MjY1NDMxNDY4ZmM1MDZm',
				APIKey: '6114812f9898749ae9ac2b6afdc5c115',
				sparkResult: '',
				historyTextList: [], // 历史会话信息，由于最大token12000,可以结合实际使用，进行移出
				tempRes: '', // 临时答复保存
				
				
				//系统信息
				systemInfo: {
					safeAreaInsets: {
						bottom: 0
					}
				},
				scrollIntoView:'',
				messages:[
					{
						"time":"",
						"icon":"https://mp-eeab6da6-80cd-4e80-844a-66b2a7203834.cdn.bspapp.com/cloudstorage/5fcdbeb8-01b2-47ac-b09f-1d1dcb1c6c60.png?x-oss-process=image/resize,m_fixed,w_160",
						"name":"AI",
						"content":"你好！有什么我可以帮助你的吗？",
						"isMe":false,
						"role":"assistant",
						"status":1,
						"chatId":1681804927670,
					},
				],
				AIinfo:{
					time: '',
					icon: 'https://mp-eeab6da6-80cd-4e80-844a-66b2a7203834.cdn.bspapp.com/cloudstorage/5fcdbeb8-01b2-47ac-b09f-1d1dcb1c6c60.png?x-oss-process=image/resize,m_fixed,w_160',
					name: 'AI',
					content: '',
					isMe: false,
					role:'assistant',
					status:0 //0 加载中 1加载完成 -1出错 2持续输出
				},
				myInfo:{
					time: '',
					icon: 'https://mp-eeab6da6-80cd-4e80-844a-66b2a7203834.cdn.bspapp.com/cloudstorage/cd62d1b0-0f65-408a-ac09-204e7576b82a.png?x-oss-process=image/resize,m_fixed,w_160',
					name: '我',
					content: '',
					isMe: true,
					role:'user',
					status:1 //0 加载中 1加载完成 -1出错 2持续输出
				},
				//键盘高度
				keyboardHeight:0,
				sendData:[]
			}
		},
		computed:{
			imPlaceholderheight() {
				let imPlaceholderheight=this.keyboardHeight+this.systemInfo.safeAreaInsets.bottom
				return imPlaceholderheight
			},
		},
		methods: {
			async concatMsg(data){
				let lastData =this.messages[this.messages.length-1]
				let sendData = [data,{role:this.myInfo.role,content:'继续'}]
				try{
					const res = await cAi.chat(sendData)
					const choice = res.choices[0]
					lastData.content += res.reply
					// this.$nextTick(this.showLast)
					if(choice.finishReason=='stop'){
						lastData.status=1
					}else{
						lastData.status=2
						this.concatMsg(choice.message)
					}
				}catch(e){
					//TODO handle the exception
					lastData.status=-1
					lastData.content = '出错了2，请稍后询问...'
					this.showLast()
					this.sendData=[]
				}
			},
			async doSend(val){
				let lastData =this.messages[this.messages.length-1]
				if(lastData.status==0||lastData.status==2){
					uni.showToast({
						title:'AI回答中，请稍后...',
						icon:'none'
					})
					return
				}
				
				let dataMy = JSON.parse(JSON.stringify(this.myInfo))
				dataMy.chatId = Date.now()
				dataMy.content = val
				this.messages.push(dataMy)
				console.log(this.messages,'this.messages')
				this.sendData.push({role:dataMy.role,content:dataMy.content})
				
				let dataAi = JSON.parse(JSON.stringify(this.AIinfo))
				dataAi.chatId = Date.now()
				this.messages.push(dataAi)
				setTimeout(this.showLast,200)
				
				lastData=this.messages[this.messages.length-1]
				try{
					const res = await cAi.chat(this.sendData)
					console.log(res);
					if(res.reply){
						const choice = res.choices[0]
						if(choice.finishReason=='stop'){
							lastData.status=1
						}else{
							lastData.status=2
							this.concatMsg(choice.message)
						}
						lastData.content = res.reply
						this.showLast()
						
						if(res.summarize){
							this.sendData=[{role:dataAi.role,content:res.summarize}]
						}else{
							this.sendData.push({role:dataAi.role,content:res.reply})
						}
					}
				}catch(e){
					//TODO handle the exception
					lastData.status=-1
					lastData.content = '出错了1，请稍后询问...'
					this.showLast()
					this.sendData=[]
				}
				// console.log(JSON.stringify(this.messages));
			},
			showLast(){
				setTimeout(()=>{
					
					// #ifndef H5
					uni.pageScrollTo({
					    scrollTop: this.systemInfo.windowHeight,
					    duration: 0
					  })
					// #endif
					this.scrollIntoView ='list-last-item'
					this.$nextTick(()=>{
						this.scrollIntoView =''
					})
				},100)
			},
			
			async sendToSpark(val) {
				let myUrl = await this.getWebSocketUrl();
				this.tempRes = "";
				let realThis = this;
				
				this.socketTask = uni.connectSocket({
					url: myUrl,
					method: 'GET',
					success: res => {
						realThis.wsLiveFlag = true;
					}
				})
				
				realThis.socketTask.onError((res) => {
					console.log("连接发生错误，请检查appid是否填写", res)
				})
				
				realThis.socketTask.onOpen((res) => {
					
					let dataMy = JSON.parse(JSON.stringify(this.myInfo))
					dataMy.chatId = Date.now()
					dataMy.content = val
					this.messages.push(dataMy)
					
					let dataAi = JSON.parse(JSON.stringify(this.AIinfo))
					dataAi.chatId = Date.now()
					this.messages.push(dataAi)
					
					
					this.historyTextList.push({
						"role": "user",
						"content": val
					})
					console.info("wss的onOpen成功执行...", res)
					// 第一帧..........................................
					console.log('open成功...')
					let params = {
						"header": {
							"app_id": this.APPID,
							"uid": "aef9f963-7"
						},
						"parameter": {
							"chat": {
								"domain": this.modelDomain,
								"temperature": 0.5,
								"max_tokens": 1024
							}
						},
						"payload": {
							"message": {
								"text": this.historyTextList
							}
						}
					};
					console.log("请求的params：" + JSON.stringify(params))
					this.sparkResult = this.sparkResult + "\r\n我：" + this.TEXT + "\r\n"
					this.sparkResult = this.sparkResult + "大模型："
					console.log("发送第一帧...", params)
					realThis.socketTask.send({ // 发送消息，，都用uni的官方版本
						data: JSON.stringify(params),
						success() {
							console.log('第一帧发送成功')
						}
					});
				});
			
				// 接受到消息时
				realThis.socketTask.onMessage((res) => {
					
					
					let lastData = this.messages[this.messages.length-1]
					lastData.status=2
					
					console.log('收到API返回的内容：', res.data);
					let obj = JSON.parse(res.data)
					// console.log("我打印的"+obj.payload);
					let dataArray = obj.payload.choices.text;
					for (let i = 0; i < dataArray.length; i++) {
						
						lastData.content = lastData.content + dataArray[i].content
						setTimeout(this.showLast,200)
						
						realThis.sparkResult = realThis.sparkResult + dataArray[i].content
						realThis.tempRes = realThis.tempRes + dataArray[i].content
					}
					
					// realThis.sparkResult =realThis.sparkResult+ 
					let temp = JSON.parse(res.data)
					// console.log("0726",temp.header.code)
					if (temp.header.code !== 0) {
						console.log(`${temp.header.code}:${temp.message}`);
						realThis.socketTask.close({
							success(res) {
								console.log('关闭成功', res)
								realThis.wsLiveFlag = false;
							},
							fail(err) {
								console.log('关闭失败', err)
							}
						})
					}
					if (temp.header.code === 0) {
						if (res.data && temp.header.status === 2) {
							lastData.status=1
							realThis.sparkResult = realThis.sparkResult +
								"\r\n**********************************************"
							this.historyTextList.push({
								"role": "assistant",
								"content": this.tempRes
							})
							/* let dataArray= obj.payload.choices.text;
							for(let i=0;i<dataArray.length;i++){
								realThis.sparkResult =realThis.sparkResult+ dataArray[i].content
							} */
							setTimeout(() => {
								realThis.socketTask.close({
									success(res) {
										console.log('关闭成功', res)
									},
									fail(err) {
										// console.log('关闭失败', err)
									}
								})
							}, 1000)
						}
					}
				})
			},
			
			// 鉴权
			getWebSocketUrl() {
				console.log(this.httpUrl)
				var httpUrlHost = (this.httpUrl).substring(8, 28);
				var httpUrlPath = (this.httpUrl).substring(28);
				console.log(httpUrlHost)
				console.log(httpUrlPath)
				switch (httpUrlPath) {
					case "/v1.1/chat":
						this.modelDomain = "general";
						break;
					case "/v2.1/chat":
						this.modelDomain = "generalv2";
						break;
					case "/v3.1/chat":
						this.modelDomain = "generalv3";
						break;
					case "/v3.5/chat":
						this.modelDomain = "generalv3.5";
						break;
				}
				console.log(this.modelDomain)
			
			
				return new Promise((resolve, reject) => {
					// https://spark-api.xf-yun.com/v1.1/chat  V1.5 domain general
					// https://spark-api.xf-yun.com/v2.1/chat  V2.0 domain generalv2
					var url = "wss://"+httpUrlHost+httpUrlPath;
					var host = "spark-api.xf-yun.com";
					var apiKeyName = "api_key";
					var date = new Date().toGMTString();
					var algorithm = "hmac-sha256";
					var headers = "host date request-line";
					var signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${httpUrlPath} HTTP/1.1`;
					var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.APISecret);
					var signature = CryptoJS.enc.Base64.stringify(signatureSha);
					var authorizationOrigin =
						`${apiKeyName}="${this.APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
					var authorization = base64.encode(authorizationOrigin);
					url = `${url}?authorization=${authorization}&date=${encodeURI(date)}&host=${host}`;
			
					// console.log(url)
					resolve(url); // 主要是返回地址
				});
			},
			
			
		},
		async onLoad() {
			this.systemInfo = uni.getSystemInfoSync()
			// #ifdef APP-PLUS
			if(this.systemInfo.safeAreaInsets.bottom==0){
				this.systemInfo.safeAreaInsets.bottom=16
			}
			// #endif
			
			// #ifdef H5
			this.systemInfo.windowHeight-=uni.upx2px(190)
			
			
			// #endif
			
			// console.log(this.systemInfo);
			// #ifndef H5
			uni.onKeyboardHeightChange(res => {
			  console.log(res.height)
			  this.keyboardHeight = res.height
			})
			// #endif
		},
		onReady() {
			this.$nextTick(this.showLast)
		},
	}
</script>

<style lang="scss">
/* #ifndef APP-NVUE */
page{
	background-color: #ffffff;
}
/* #endif */
.page{

}
.bottom{
	position: fixed;
	bottom: 0;
	width: 100%;
	background-color: #f8f8f8;
}

// .safe-bottom{
// 	padding-bottom: constant(safe-area-inset-bottom)!important;
// 	padding-bottom: env(safe-area-inset-bottom) !important;
// }
.msg-list{
	// height: 100vh;
	
}
.list-last-item{
	height: 80px;
}
</style>
